
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using UnityEditor;
using UnityEditor.Android;
using UnityEngine;

internal class ModifyAndroidManifest :IPostGenerateGradleAndroidProject
{
    public int callbackOrder => 1;



    protected void OnPostGenerateGradleAndroidProjectExt(string path) {
        //Debug.Log("===>"+path);//Temp\gradleOut\unityLibrary
        var androidManifest = new AndroidManifest(GetManifestPath(path));
        androidManifest.AddMetaData();
        androidManifest.Save();
    }


    private string _manifestFilePath;

    private string GetManifestPath(string basePath) {
        if ( !string.IsNullOrEmpty(_manifestFilePath) ) return _manifestFilePath;

        var pathBuilder = new StringBuilder(basePath);
        pathBuilder.Append(Path.DirectorySeparatorChar).Append("src");
        pathBuilder.Append(Path.DirectorySeparatorChar).Append("main");
        pathBuilder.Append(Path.DirectorySeparatorChar).Append("AndroidManifest.xml");
        _manifestFilePath = pathBuilder.ToString();

        return _manifestFilePath;
    }

    public void OnPostGenerateGradleAndroidProject(string path) {
        //if ( BuildTarget.Android )
        //    return;

        OnPostGenerateGradleAndroidProjectExt(path);
    }

    private class AndroidXmlDocument :XmlDocument
    {
        private string m_Path;
        protected XmlNamespaceManager nsMgr;
        public readonly string AndroidXmlNamespace = "http://schemas.android.com/apk/res/android";

        public AndroidXmlDocument(string path) {
            m_Path = path;
            using ( var reader = new XmlTextReader(m_Path) ) {
                reader.Read();
                Load(reader);
            }

            nsMgr = new XmlNamespaceManager(NameTable);
            nsMgr.AddNamespace("android", AndroidXmlNamespace);
        }

        public string Save() {
            return SaveAs(m_Path);
        }

        public string SaveAs(string path) {
            using ( var writer = new XmlTextWriter(path, new UTF8Encoding(false)) ) {
                writer.Formatting = Formatting.Indented;
                Save(writer);
            }

            return path;
        }
    }

    private class AndroidManifest :AndroidXmlDocument
    {
        private readonly XmlElement ApplicationElement;
        private readonly XmlElement ActivityIntentFilterElement;
        private readonly XmlElement ActivityElement;
        private readonly XmlElement ManifestElement;

        public AndroidManifest(string path) : base(path) {
            ApplicationElement = SelectSingleNode("/manifest/application") as XmlElement;
            ActivityIntentFilterElement = SelectSingleNode("/manifest/application/activity/intent-filter") as XmlElement;
            ActivityElement = SelectSingleNode("manifest/application/activity") as XmlElement;
            ManifestElement = SelectSingleNode("/manifest") as XmlElement;
        }

        private XmlAttribute CreateAndroidAttribute(string key, string value) {
            XmlAttribute attr = CreateAttribute("android", key, AndroidXmlNamespace);
            attr.Value = value;
            return attr;
        }

        private void UpdateOrCreateAttribute(XmlElement xmlParentElement, string tag, string name, params (string name, string value)[] attributes) {
            var xmlNodeList = xmlParentElement.SelectNodes(tag);
            XmlElement targetNode = null;

            // Check all XmlNodes to see if a node with matching name already exists.
            foreach ( XmlNode node in xmlNodeList ) {
                XmlAttribute nameAttr = (XmlAttribute)node.Attributes.GetNamedItem("name", AndroidXmlNamespace);
                if ( nameAttr != null && nameAttr.Value.Equals(name) ) {
                    targetNode = (XmlElement)node;
                    break;
                }
            }

            // If node exists, update the attribute values if they are present or create new ones as requested. Else, create new XmlElement.
            if ( targetNode != null ) {
                for ( int i = 0; i < attributes.Length; i++ ) {
                    XmlAttribute attr = (XmlAttribute)targetNode.Attributes.GetNamedItem(attributes[i].name, AndroidXmlNamespace);
                    if ( attr != null ) {
                        attr.Value = attributes[i].value;
                    } else {
                        targetNode.SetAttribute(attributes[i].name, AndroidXmlNamespace, attributes[i].value);
                    }
                }
            } else {
                XmlElement newElement = CreateElement(tag);
                newElement.SetAttribute("name", AndroidXmlNamespace, name);
                for ( int i = 0; i < attributes.Length; i++ )
                    newElement.SetAttribute(attributes[i].name, AndroidXmlNamespace, attributes[i].value);
                xmlParentElement.AppendChild(newElement);
            }
        }

        void RemoveNameValueElementInTag(string parentPath, string tag, string name, string value) {
            var xmlNodeList = this.SelectNodes(parentPath + "/" + tag);

            foreach ( XmlNode node in xmlNodeList ) {
                var attributeList = ((XmlElement)node).Attributes;

                foreach ( XmlAttribute attrib in attributeList ) {
                    if ( attrib.Name == name && attrib.Value == value ) {
                        node.ParentNode?.RemoveChild(node);
                    }
                }
            }
        }

        private List<XmlElement> FindActivitys() {
            List<XmlElement> activityList = new List<XmlElement>();

            var xmlNodeList = ApplicationElement.SelectNodes("activity");

            foreach ( XmlNode node in xmlNodeList ) {
                XmlAttribute nameAttr = (XmlAttribute)node.Attributes.GetNamedItem("name", AndroidXmlNamespace);
                //Debug.Log(nameAttr.Value);
                activityList.Add((XmlElement)node);
            }

            //XmlElement targetNode = null;

            //// Check all XmlNodes to see if a node with matching name already exists.
            //foreach ( XmlNode node in xmlNodeList ) {
            //    XmlAttribute nameAttr = (XmlAttribute)node.Attributes.GetNamedItem("name", AndroidXmlNamespace);
            //    Debug.Log(nameAttr.Value);
            //    if ( nameAttr != null && nameAttr.Value.Equals("android.intent.category.LAUNCHER") ) {
            //        targetNode = (XmlElement)node;
            //        break;
            //    }
            //}
            return activityList;

        } 

        internal void AddMetaData() {

            //UpdateOrCreateAttribute(ActivityIntentFilterElement,
            //    "category", "com.oculus.intent.category.VR"
            //    );

            //UpdateOrCreateAttribute(ActivityElement,
            //    "meta-data", "com.oculus.vr.focusaware",
            //    new (string name, string value)[] {
            //            ("value", "true")
            //    });

            //UpdateOrCreateAttribute(ManifestElement,
            //    "uses-feature", "android.hardware.vr.headtracking",
            //    new (string name, string value)[] {
            //            ("required", "true"),
            //            ("version", "1")
            //    });
            List<XmlElement> activityList = FindActivitys();
            //add 
            foreach ( XmlElement activity in activityList ) {
                XmlAttribute nameAttr = (XmlAttribute)activity.Attributes.GetNamedItem("name", AndroidXmlNamespace);
                //Debug.Log(nameAttr.Value);


                UpdateOrCreateAttribute(ApplicationElement,
"activity", nameAttr.Value, /* "com.unity3d.player.UnityPlayerActivity" */
new (string name, string value)[] {
                        ("resizeableActivity", "true"),
                        ("hardwareAccelerated", "true")
});

  //<application>
  //  <activity android:name="com.unity3d.player.UnityPlayerActivity" android:theme="@style/UnityThemeSelector" 
  //                  android:screenOrientation="fullUser" android:launchMode="singleTask" 
  //                  android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density" 
  //                  android:resizeableActivity="true" android:hardwareAccelerated="true">
            }




//AndroidManifest.xml Demo

//            <?xml version="1.0" encoding="utf-8"?>
//<!-- GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN-->
//<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.unity3d.player" xmlns:tools="http://schemas.android.com/tools">
//  <application>
//    <activity android:name="com.unity3d.player.UnityPlayerActivity" android:theme="@style/UnityThemeSelector" android:screenOrientation="fullUser" android:launchMode="singleTask" android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density" android:resizeableActivity="true" android:hardwareAccelerated="true">
//      <intent-filter>
//        <action android:name="android.intent.action.MAIN" />
//        <category android:name="android.intent.category.LAUNCHER" />
//        <category android:name="com.oculus.intent.category.VR" />
//      </intent-filter>
//      <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
//      <meta-data android:name="android.notch_support" android:value="true" />
//      <meta-data android:name="com.oculus.vr.focusaware" android:value="true" />
//    </activity>
//    <meta-data android:name="unity.splash-mode" android:value="0" />
//    <meta-data android:name="unity.splash-enable" android:value="True" />
//    <meta-data android:name="unity.allow-resizable-window" android:value="False" />
//    <meta-data android:name="notch.config" android:value="portrait|landscape" />
//    <meta-data android:name="unity.build-id" android:value="c2bbd279-b214-4640-9d1b-af0e418b4eef" />
//  </application>
//  <uses-feature android:glEsVersion="0x00030000" />
//  <uses-permission android:name="android.permission.INTERNET" />
//  <uses-feature android:name="android.hardware.touchscreen" android:required="false" />
//  <uses-feature android:name="android.hardware.touchscreen.multitouch" android:required="false" />
//  <uses-feature android:name="android.hardware.touchscreen.multitouch.distinct" android:required="false" />
//  <uses-feature android:name="android.hardware.vr.headtracking" android:required="true" android:version="1" />
//</manifest>


            // if the Microphone class is used in a project, the BLUETOOTH permission is automatically added to the manifest
            // we remove it here since it will cause projects to fail Meta cert
            // this shouldn't affect Bluetooth HID devices, which don't need the permission
            //RemoveNameValueElementInTag("/manifest", "uses-permission", "android:name", "android.permission.BLUETOOTH");
        }
    }
}
